agentmux_srv\backend\utilfn/
hash.rs1#![allow(dead_code)]
2pub fn sha1_hash(data: &[u8]) -> String {
10 let mut hasher = Sha1::new();
11 hasher.update(data);
12 let result = hasher.finalize();
13 base64_encode(&result)
14}
15
16pub fn quick_hash_string(s: &str) -> String {
18 let mut hasher = Fnv64a::new();
19 hasher.update(s.as_bytes());
20 let result = hasher.finalize();
21 base64_url_encode(&result)
22}
23
24struct Sha1 {
27 state: [u32; 5],
28 count: u64,
29 buffer: [u8; 64],
30 buffer_len: usize,
31}
32
33impl Sha1 {
34 fn new() -> Self {
35 Self {
36 state: [0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476, 0xC3D2E1F0],
37 count: 0,
38 buffer: [0u8; 64],
39 buffer_len: 0,
40 }
41 }
42
43 fn update(&mut self, data: &[u8]) {
44 let mut i = 0;
45 self.count += data.len() as u64;
46 if self.buffer_len > 0 {
47 let space = 64 - self.buffer_len;
48 let copy_len = std::cmp::min(space, data.len());
49 self.buffer[self.buffer_len..self.buffer_len + copy_len].copy_from_slice(&data[..copy_len]);
50 self.buffer_len += copy_len;
51 i = copy_len;
52 if self.buffer_len == 64 {
53 let block = self.buffer;
54 self.process_block(&block);
55 self.buffer_len = 0;
56 }
57 }
58 while i + 64 <= data.len() {
59 let mut block = [0u8; 64];
60 block.copy_from_slice(&data[i..i + 64]);
61 self.process_block(&block);
62 i += 64;
63 }
64 if i < data.len() {
65 let remaining = data.len() - i;
66 self.buffer[..remaining].copy_from_slice(&data[i..]);
67 self.buffer_len = remaining;
68 }
69 }
70
71 #[allow(clippy::needless_range_loop)]
72 fn process_block(&mut self, block: &[u8; 64]) {
73 let mut w = [0u32; 80];
74 for i in 0..16 {
75 w[i] = u32::from_be_bytes([block[i * 4], block[i * 4 + 1], block[i * 4 + 2], block[i * 4 + 3]]);
76 }
77 for i in 16..80 {
78 w[i] = (w[i - 3] ^ w[i - 8] ^ w[i - 14] ^ w[i - 16]).rotate_left(1);
79 }
80 let [mut a, mut b, mut c, mut d, mut e] = self.state;
81 for i in 0..80 {
82 let (f, k) = match i {
83 0..=19 => ((b & c) | ((!b) & d), 0x5A827999u32),
84 20..=39 => (b ^ c ^ d, 0x6ED9EBA1u32),
85 40..=59 => ((b & c) | (b & d) | (c & d), 0x8F1BBCDCu32),
86 _ => (b ^ c ^ d, 0xCA62C1D6u32),
87 };
88 let temp = a.rotate_left(5).wrapping_add(f).wrapping_add(e).wrapping_add(k).wrapping_add(w[i]);
89 e = d;
90 d = c;
91 c = b.rotate_left(30);
92 b = a;
93 a = temp;
94 }
95 self.state[0] = self.state[0].wrapping_add(a);
96 self.state[1] = self.state[1].wrapping_add(b);
97 self.state[2] = self.state[2].wrapping_add(c);
98 self.state[3] = self.state[3].wrapping_add(d);
99 self.state[4] = self.state[4].wrapping_add(e);
100 }
101
102 fn finalize(mut self) -> [u8; 20] {
103 let bit_count = self.count * 8;
104 let mut padding = vec![0x80u8];
106 let pad_len = if self.buffer_len < 56 {
107 56 - self.buffer_len - 1
108 } else {
109 120 - self.buffer_len - 1
110 };
111 padding.extend(std::iter::repeat_n(0u8, pad_len));
112 padding.extend_from_slice(&bit_count.to_be_bytes());
113 self.update(&padding);
114
115 let mut result = [0u8; 20];
116 for (i, &s) in self.state.iter().enumerate() {
117 result[i * 4..i * 4 + 4].copy_from_slice(&s.to_be_bytes());
118 }
119 result
120 }
121}
122
123struct Fnv64a {
126 hash: u64,
127}
128
129impl Fnv64a {
130 const OFFSET_BASIS: u64 = 0xcbf29ce484222325;
131 const PRIME: u64 = 0x100000001b3;
132
133 fn new() -> Self {
134 Self { hash: Self::OFFSET_BASIS }
135 }
136
137 fn update(&mut self, data: &[u8]) {
138 for &b in data {
139 self.hash ^= b as u64;
140 self.hash = self.hash.wrapping_mul(Self::PRIME);
141 }
142 }
143
144 fn finalize(&self) -> [u8; 8] {
145 self.hash.to_be_bytes()
146 }
147}
148
149fn base64_encode(data: &[u8]) -> String {
152 const CHARS: &[u8] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
153 let mut result = String::new();
154 let mut i = 0;
155 while i < data.len() {
156 let b0 = data[i] as u32;
157 let b1 = if i + 1 < data.len() { data[i + 1] as u32 } else { 0 };
158 let b2 = if i + 2 < data.len() { data[i + 2] as u32 } else { 0 };
159 let triple = (b0 << 16) | (b1 << 8) | b2;
160 result.push(CHARS[((triple >> 18) & 0x3F) as usize] as char);
161 result.push(CHARS[((triple >> 12) & 0x3F) as usize] as char);
162 if i + 1 < data.len() {
163 result.push(CHARS[((triple >> 6) & 0x3F) as usize] as char);
164 } else {
165 result.push('=');
166 }
167 if i + 2 < data.len() {
168 result.push(CHARS[(triple & 0x3F) as usize] as char);
169 } else {
170 result.push('=');
171 }
172 i += 3;
173 }
174 result
175}
176
177fn base64_url_encode(data: &[u8]) -> String {
178 const CHARS: &[u8] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
179 let mut result = String::new();
180 let mut i = 0;
181 while i < data.len() {
182 let b0 = data[i] as u32;
183 let b1 = if i + 1 < data.len() { data[i + 1] as u32 } else { 0 };
184 let b2 = if i + 2 < data.len() { data[i + 2] as u32 } else { 0 };
185 let triple = (b0 << 16) | (b1 << 8) | b2;
186 result.push(CHARS[((triple >> 18) & 0x3F) as usize] as char);
187 result.push(CHARS[((triple >> 12) & 0x3F) as usize] as char);
188 if i + 1 < data.len() {
189 result.push(CHARS[((triple >> 6) & 0x3F) as usize] as char);
190 }
191 if i + 2 < data.len() {
192 result.push(CHARS[(triple & 0x3F) as usize] as char);
193 }
194 i += 3;
195 }
196 result
197}